package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.model.CartInfo;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.SkuInfo;
import io.swagger.models.auth.In;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: atguigu
 * @create: 2023-06-21 10:14
 */
@Service
public class CartServiceImpl implements CartService {


    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    private ProductFeignClient productFeignClient;


    /**
     * 将"用户"选择商品加入到购物车
     *
     * @param userId 用户ID
     * @param skuId  商品ID
     * @param num    购买数量
     */
    @Override
    public void addToCart(String userId, Long skuId, Integer num) {
        //1.拼接当前用户购物车hash结构redisKey,创建hash结构操作对象  user:用户ID:cart
        String redisKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //创建操作对象传入hash结构的RedisKey 这个操作对象只会操作某个用户购物车hash
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(redisKey);
        //TODO 判断当前用户购物车中商品数量 业务限制
        int size = hashOps.keys().size();
        if (size >= 50) {
            throw new RuntimeException("购物车数量超限!");
        }

        //2.判断加入商品ID是否包含在 hashKey
        String hashKey = skuId.toString();
        CartInfo cartInfo = null;
        if (hashOps.hasKey(hashKey)) {
            //3.如果存在完成商品数量累加
            cartInfo = hashOps.get(hashKey);
            //3.1 先获取购物车中商品信息 修改数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + num);
        } else {
            //4.如果不存在商品新增 其中商品信息远程调用商品服务获取
            //4.1 远程调用商品微服务获取商品信息 TODO 异步编排+线程池优化
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //4.2 远程调用商品微服务获取商品价格
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            //4.3 构建购物车商品对象
            cartInfo = new CartInfo();
            cartInfo.setId(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setCartPrice(skuPrice);
            cartInfo.setSkuPrice(skuPrice);
            cartInfo.setSkuNum(num);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
        }
        //5 将购物车商品写回到Redis
        hashOps.put(hashKey, cartInfo);
    }


    /**
     * 获取当前"用户"购物车列表,涉及到合并-不合并版本
     *
     * @param userId     用户ID
     * @param userTempId 临时用户ID
     * @return
     */
    //@Override
    //public List<CartInfo> getCartList(String userId, String userTempId) {
    //    //1.判断用户是否已登录 直接返回已登录购物车列表(按照创建时间排序-倒序)
    //    if (StringUtils.isNotBlank(userId)) {
    //        //1.1 创建用户购物车hash结构key
    //        String loginKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    //        //1.2 创建hash操作对象
    //        BoundHashOperations<String, String, CartInfo> loginHashOps = redisTemplate.boundHashOps(loginKey);
    //        //1.3 获取该购物车中所有商品列表
    //        List<CartInfo> loginCartList = loginHashOps.values();
    //        //1.4 对数据进行排序-自定义排序规则
    //        loginCartList = loginCartList.stream().sorted((o1, o2) -> {
    //            return DateUtil.truncatedCompareTo(o1.getCreateTime(), o2.getCreateTime(), Calendar.MILLISECOND);
    //        }).collect(Collectors.toList());
    //        return loginCartList;
    //    }
    //
    //    //2.判断是否为临时用户 直接返回未登录购物车列表(按照创建时间排序-倒序)
    //    if (StringUtils.isNotBlank(userTempId)) {
    //        //2.1 创建临时用户购物车hash结构key
    //        String noLoginKey = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
    //        //2.2 创建hash操作对象
    //        BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLoginKey);
    //        //2.3 获取该购物车中所有商品列表
    //        List<CartInfo> noLoginCartList = noLoginHashOps.values();
    //        //2.4 对数据进行排序-自定义排序规则
    //        noLoginCartList = noLoginCartList.stream().sorted((o1, o2) -> {
    //            return DateUtil.truncatedCompareTo(o1.getCreateTime(), o2.getCreateTime(), Calendar.MILLISECOND);
    //        }).collect(Collectors.toList());
    //        return noLoginCartList;
    //    }
    //    return null;
    //}


    /**
     * 获取当前"用户"购物车列表,涉及到合并-合并版本
     *
     * @param userId     用户ID
     * @param userTempId 临时用户ID
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {

        //1.先尝试获取临时用户未登录购物车列表
        List<CartInfo> noLoginCartList = null;
        String noLoginKey = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
        if (StringUtils.isNotBlank(userTempId)) {
            //1.1 创建临时用户购物车hash结构key
            //1.2 创建hash操作对象
            BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLoginKey);
            //1.3 获取该购物车中所有商品列表
            noLoginCartList = noLoginHashOps.values();
        }
        //2.如果用户未登录 直接返回未登录购物车
        if (StringUtils.isBlank(userId)) {
            //对数据进行排序-自定义排序规则
            if (!CollectionUtils.isEmpty(noLoginCartList)) {
                noLoginCartList = noLoginCartList.stream().sorted((o1, o2) -> {
                    return DateUtil.truncatedCompareTo(o1.getCreateTime(), o2.getCreateTime(), Calendar.MILLISECOND);
                }).collect(Collectors.toList());
                return noLoginCartList;
            }
        }

        //3.用户登录 合并条件:未登录购物车集合不为空
        //3.1 创建用户购物车hash接口key 创建操作登录购车车hash操作对象
        String loginKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        ///1.2 创建hash操作对象
        BoundHashOperations<String, String, CartInfo> loginHashOps = redisTemplate.boundHashOps(loginKey);

        //4.合并购物车 循环未登录购物车列表 判断 已登录用户购车hash结构中是否包含商品SkuId
        if (!CollectionUtils.isEmpty(noLoginCartList)) {
            noLoginCartList.stream().forEach(noLoginCart -> {
                //4.1 判断当前登录用户购物车中是否包含该商品
                String hashKey = noLoginCart.getSkuId().toString();
                if (loginHashOps.hasKey(hashKey)) {
                    //4.2 包含:获取购物车商品信息对数值累加
                    CartInfo loginCartInfo = loginHashOps.get(hashKey);
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + noLoginCart.getSkuNum());
                    loginHashOps.put(hashKey, loginCartInfo);
                } else {
                    //4.3 不包含:将未登录购车商品对象新增到登录购物车中 todo:关联登录用户ID
                    noLoginCart.setUserId(userId);
                    noLoginCart.setUpdateTime(new Date());
                    loginHashOps.put(hashKey, noLoginCart);
                }
            });
        }
        //5.清理未登录购车
        redisTemplate.delete(noLoginKey);
        //6.查询登录用户购物车列表
        List<CartInfo> cartInfoList = loginHashOps.values();

        //7.对合并后购物车列表进行排序
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o1.getCreateTime(), o2.getCreateTime(), Calendar.MILLISECOND);
            }).collect(Collectors.toList());
            return cartInfoList;
        }
        return new ArrayList<>();
    }

    /**
     * 修改当前用户指定购物车商品选中状态
     *
     * @param userId
     * @param skuId
     * @param ischecked
     */
    @Override
    public void updateCheckState(String userId, Long skuId, int ischecked) {
        BoundHashOperations<String, String, CartInfo> hashOps = getUserCartHashOps(userId);
        String hashKey = skuId.toString();
        if (hashOps.hasKey(hashKey)) {
            CartInfo cartInfo = hashOps.get(hashKey);
            cartInfo.setIsChecked(ischecked);
            hashOps.put(hashKey, cartInfo);
        }
    }

    /**
     * 删除指定购物车商品
     *
     * @param userId
     * @param skuId
     * @return
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        BoundHashOperations<String, String, CartInfo> hashOps = getUserCartHashOps(userId);
        hashOps.delete(skuId.toString());
    }

    /**
     * 查询指定用户购物车中选中商品列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        //1.获取用户购物车hash操作对象
        BoundHashOperations<String, String, CartInfo> hashOps = getUserCartHashOps(userId.toString());
        //2.获取所有购物车商品列表
        List<CartInfo> cartInfoList = hashOps.values();

        //3.过滤获取选中商品
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList.stream().filter((cartInfo -> {
                //Stream流中过滤 返回结果 true:需要的数据
                return cartInfo.getIsChecked().intValue() == 1;
            })).collect(Collectors.toList());
            return cartInfoList;
        }
        return null;
    }


    /**
     * 获取指定"用户"hash操作对象
     *
     * @param userId
     * @return
     */
    private BoundHashOperations<String, String, CartInfo> getUserCartHashOps(String userId) {
        String redisKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(redisKey);
        return hashOps;
    }

    public static void main(String[] args) {
        //结论:Integer包装类型 值在 -128~127之间 ==判断返回true  内部 IntegerCache缓存"常用数值"
        Integer a = 127;
        Integer b = 127;
        System.out.println(a == b);
    }
}
